package it.intecs.pisa.smarcos.activities;

import it.intecs.pisa.smarcos.R;
import it.intecs.pisa.smarcos.base.BeepManager;
import it.intecs.pisa.smarcos.base.SpeechManager;

import java.io.IOException;
import java.util.List;
import java.util.Locale;

import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Vibrator;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class Around extends BaseActivity
{
	public static final String INTENT_SHOW="it.intecs.pisa.smarcos.activities.Around.SHOW";
	private static final String TAG = Around.class.getSimpleName();
	private static final int SENSOR_RATE = 20;
	
	private View view; 
	private TextView textView;
	//private Lists list;
	private ViewGroup baseCenterView;
	private String position;
	private String actualDirection = "Empty";
	private Vibrator vibrator;
	private BeepManager beepManager;
	private SpeechManager speechManager;
	private Geocoder geocoder;
	private LocationManager locationManager;
	private GPSLocationListener locationListener;
    private SensorManager sensorManager = null;
    private OrientationListener ol;
    private String myPosition;
    private String lastInformation;
    
    private float bAzimuth = SENSOR_RATE;
    private float azimuth;
    private double latitude;
    private double longitude;
    private double lastLat;
    private double lastLon;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)    {
        super.onCreate(savedInstanceState);
        
        Log.d(TAG, "OnCreate");

		speechManager = SpeechManager.getInstance(getApplicationContext());
		beepManager = BeepManager.getInstance(getApplicationContext());
		vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);

		// Metodo di BaseViewManager
		Init(getBaseContext());
		inflater = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
		view = inflater.inflate(R.layout.generic_option, null);
		setContentView(getBaseView());
		baseCenterView = (ViewGroup) findViewById(R.id.center_base_view);
		baseCenterView.addView(view);	
		
		textView = (TextView) findViewById(R.id.Option);
		
		position = getString(R.string.TTS_Around);
		
		geocoder = new Geocoder(this, Locale.getDefault());
		
		// GPS
		locationListener = new GPSLocationListener();
		locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
		locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
		//locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
			
		// Orientation
        ol = new OrientationListener();
        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        sensorManager.registerListener(ol, sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION), SensorManager.SENSOR_DELAY_NORMAL);
    
        latitude = 0;
        longitude = 0;
        myPosition = null;
    }
    
    @Override
    public void onDestroy(){
    	sensorManager.unregisterListener(ol);
    	locationManager.removeUpdates(locationListener);
    	super.onDestroy();
    }
    
	// CLOSE
	@Override
	public void onClick_A(){
		Log.d(TAG, "onClick_A");

		Intent intent;
		intent=new Intent("it.intecs.pisa.smarcos.services.ResultReceiver.SHOW");
		intent.putExtra("Result", "NORESULT");
		intent.addCategory(Intent.CATEGORY_DEFAULT);
		sendBroadcast(intent);
		sentResult = true;
		finish();	
	}
	
	// POSITION
	@Override
	public void onClick_B(){
		Log.d(TAG, "onClick_B");
		
		speechManager.say(position, true, true);
	}
	
	// REPEAT 
	@Override
	public void onClick_C(){
		Log.d(TAG, "onClick_C");
		speechManager.say(lastInformation, true, true);
	}

	// BACK - DONE
	@Override
	public void onClick_D(){

		onClick_A();
		Log.d(TAG, "onClick_D");
	}
	
	
	private class GPSLocationListener implements LocationListener {

		private final String TAG = GPSLocationListener.class.getSimpleName();
		
		  public void onLocationChanged(Location arg0) {
		    latitude = arg0.getLatitude();
		    longitude = arg0.getLongitude();
		    
		    myPosition();
		    
		    Log.d(TAG, "latitude " + latitude + " longitude " + longitude);
		  }

		  public void onProviderDisabled(String provider) {}

		  public void onProviderEnabled(String provider) { }

		  public void onStatusChanged(String provider, int status, Bundle extras) {}
	}	
	
	

	private class OrientationListener implements SensorEventListener {
	
		boolean foundStreet = false;
		boolean directionChanged = false;
			
		public void onSensorChanged(SensorEvent event) {
			
			// Aspetta che il sensore GPS abbia fatto la prima rilevazione.
			if (latitude == 0.0 && longitude == 0.0)
				return;

			azimuth = event.values[0];

			directionChanged = changedDirection();

			if ((Math.abs(bAzimuth - azimuth) <= 20.0) && directionChanged == false && foundStreet == true)
				return;	

			Log.d (TAG, "---------------  onSensorChanged ------------------");
			bAzimuth = azimuth;

			if (foundStreet == false && directionChanged == false){
				Log.d (TAG, "onSensorChanged - RECALL");
				foundStreet = findNearby(lastLat, lastLon);
			}

			if (directionChanged == true) {
				Log.d (TAG, "onSensorChanged - NEWCALL");
				foundStreet = findNearby(latitude, longitude);
			}
		}

		public void onAccuracyChanged(Sensor arg0, int arg1){}
	}


	private boolean changedDirection(){

		String direction = "";
		
		if (((azimuth >= 0) && (azimuth < 20)) || ((azimuth >= 340) && (azimuth < 360)))
			direction = "Nord";
		if (((azimuth >= 20) && (azimuth < 80)))
			direction = "Nord Est";
		if (((azimuth >= 80) && (azimuth < 110)))
			direction = "Est";
		if (((azimuth >= 110) && (azimuth < 160)))
			direction = "Sud Est";
		if (((azimuth >= 160) && (azimuth < 200)))
			direction = "Sud";
		if (((azimuth >= 200) && (azimuth < 250)))
			direction = "Sud Ovest";
		if (((azimuth >= 250) && (azimuth < 290)))
			direction = "Ovest";
		if (((azimuth >= 290) && (azimuth < 340)))
			direction = "Nord Ovest";
		
		if (!actualDirection.equals(direction)) {
			actualDirection = direction;
			speechManager.say(actualDirection, true, false);
			return true;
		}	
		
		return false;
	}
	
	
	private boolean findNearby(double nLatitude, double nLongitude) {
		
		final double DISTANCE = 0.0001;
		List<Address> addresses = null;
	
		nLatitude += DISTANCE * Math.cos(azimuth*Math.PI/180);
		nLongitude += DISTANCE * Math.sin(azimuth*Math.PI/180);
		
		addresses = handleGeocoder(nLatitude, nLongitude);

		if (addresses != null && !addresses.isEmpty()){
	
			lastInformation = addresses.get(0).getAddressLine(0);
			
			Log.d(TAG, "featureName " + addresses.get(0).getFeatureName() + " premises " + addresses.get(0).getPremises());
			
			Log.d(TAG, "SEARCHING DIRECTION " + actualDirection + " azimuth " + azimuth);
			Log.d(TAG, "MY POSITION " + myPosition + " NEAREST STREAT " + lastInformation);
			
			if (!lastInformation.equals(myPosition)){
				speechManager.say(lastInformation, true, false);
				textView.setText(actualDirection + "\n" + lastInformation);
				Log.d(TAG, nLatitude + " " + nLongitude);
				Log.d(TAG, addresses.toString());
				lastLat = 0.0;
				lastLon = 0.0;
				return true;
			}
		}

		lastLat = nLatitude;
		lastLon = nLongitude;
		return false;
	}
	
	
	List<Address> handleGeocoder(double lat, double lon){
		
		List<Address> addresses;
		
		try {
			addresses = geocoder.getFromLocation(lat, lon, 1);
			//addresses = geocoder.getFromLocation(43.656683,10.438218, 5);
			//addresses = geocoder.getFromLocation(43.655228,10.437493, 5);
		
		} catch (IOException e){
			Log.d(TAG, "The network is unavailable or an I/O problem occurs ");
			return null;
		} catch (IllegalArgumentException e){
			Log.d(TAG, "Latitude is less than -90 or greater than 90 or ");
			Log.d(TAG, "Longitude is less than -180 or greater than 180");
			return null;
		}
		return addresses;
	}
	
	
	private Boolean myPosition() {
		
		List<Address> addresses = handleGeocoder(latitude, longitude);
		
		if (addresses == null || addresses.isEmpty())
			myPosition = getString(R.string.TTS_NoStreet);
		else
			myPosition = addresses.get(0).getAddressLine(0);

		lastInformation = myPosition;
		Log.d(TAG, "MY POSITION " + myPosition);
		return true;
	}
}

